home *** CD-ROM | disk | FTP | other *** search
- >From: maart@nat.vu.nl (Maarten Litmaath)
- Newsgroups: comp.sources.misc
- Subject: v17i012: which6 - fast which(1) version 6, Part01/01
- Message-ID: <1991Feb22.021009.15138@sparky.IMD.Sterling.COM>
- Date: 22 Feb 91 02:10:09 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Checksum-Snefru: 94c3a9b1 c13eb623 1350a826 8e7dad30
-
- Submitted-by: Maarten Litmaath <maart@nat.vu.nl>
- Posting-number: Volume 17, Issue 12
- Archive-name: which6/part01
-
- I've included the latest version of the `fast which' program. Though the
- changes are small, I decided to resubmit the source in its entirety, because
- a patch, which is always a hassle, would not have been substantially smaller.
-
- This sixth version supersedes the following issues, which can be deleted
- from the archives (or replaced with pointers to `which6'):
-
- v04i010, v05i016, v10i064, and v11i096
-
- Maarten Litmaath <maart@nat.vu.nl>
-
- : This is a shar archive. Extract with sh, not csh.
- : This archive ends with exit, so do not worry about trailing junk.
- : --------------------------- cut here --------------------------
- PATH=/bin:/usr/bin:/usr/ucb
- echo Extracting 'which6.c'
- sed 's/^X//' > 'which6.c' << '+ END-OF-FILE ''which6.c'
- X/*
- X * which [-i] [-a] [--] [<command>]
- X * alias which alias !\$ \| /usr/local/bin/which -i !\*
- X * alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}'
- X * which()
- X * {
- X * eval last=\"\$$#\"
- X * set | sed -n "/^$last(){$/,/^}$/p" |
- X * /usr/local/bin/which -i ${1+"$@"}
- X * }
- X *
- X * Author: Maarten Litmaath @ VU University Amsterdam (maart@cs.vu.nl)
- X *
- X * First change:
- X * Emile LeBlanc (leblanc%math.Berkeley.EDU@ucbvax.berkeley.edu) notes
- X * the access() system call considering everything executable for
- X * root (!), so we give root a special treatment. :-(
- X * `which', `which -i' and `which -a' with no further arguments now
- X * return the PATH environment variable, split up into its components.
- X * The aliases defined above are slightly different from the previous
- X * version - now it's the shell who's doing the alias checking.
- X * Second change:
- X * Added support for shell functions and multiline aliases, added the
- X * `--' option, changed the source style.
- X * Third change:
- X * To hell with access()!
- X * Now stat() is used to give the right answer even if the effective
- X * uid (gid) differs from the real uid (gid).
- X * We can't use setuid(geteuid()), because that's nonportable. :-(
- X * Fourth change:
- X * Jim Meyering <meyering@cs.utexas.edu> notes convert() will clobber
- X * the stack if the PATH is longer than BUF_SIZE - 1 characters.
- X * I've changed convert() altogether to return a path vector (cf. argv),
- X * whose components are the respective directories in the PATH.
- X * Furthermore in printing the PATH there are no trailing colons anymore.
- X * Fifth change:
- X * I've added support for multiple groups (see getgroups(2) on BSD-
- X * derivatives).
- X * Thanks to John M. Sellens <jmsellens@watdragon.uwaterloo.ca> (and
- X * Andy at the same site).
- X * Furthermore, if a matching executable is found in an unreadable
- X * directory, beside the warning on stderr the name is now printed on
- X * stdout as well.
- X */
- X
- X#ifdef MULTIPLE_GROUPS
- X#include <sys/param.h>
- X#else
- X#include <sys/types.h>
- X#endif /* MULTIPLE_GROUPS */
- X#include <sys/stat.h>
- X#include <stdio.h>
- X
- X#define BUF_SIZE 512
- X#define M_USR 0700
- X#define M_GRP 0070
- X#define M_OTH 0007
- X#define X_ALL 0111
- X#define R_ALL 0444
- X
- Xchar Version[] =
- X "@(#)which 6.0 91/02/02 Maarten Litmaath @ VU Informatika Amsterdam";
- Xchar *Prog;
- X
- X
- Xvoid usage()
- X{
- X fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog);
- X exit(1);
- X}
- X
- X
- Xmain(argc, argv)
- Xint argc;
- Xregister char **argv;
- X{
- X register char *path, *s, **pathv, **p;
- X char *strcpy(), *getenv(), *fgets(), buf[BUF_SIZE], **convert();
- X int all = 0, inter = 0, stop = 0, found = 0, uid, gid, mask,
- X xmask, rmask;
- X struct stat st;
- X void usage();
- X
- X
- X Prog = *argv++;
- X --argc;
- X
- X while (!stop && (s = *argv) && (*s == '-')) {
- X ++argv;
- X --argc;
- X ++s;
- X while (*s)
- X switch (*s++) {
- X case 'a':
- X all = 1;
- X break;
- X case 'i':
- X inter = 1;
- X break;
- X case '-':
- X stop = 1;
- X break;
- X default:
- X usage();
- X }
- X }
- X
- X if (argc > 1)
- X usage();
- X
- X if (inter && *argv) {
- X while (fgets(buf, sizeof buf, stdin)) {
- X if (!found) {
- X printf("%s", *argv);
- X found = 1;
- X }
- X printf("\t%s", buf);
- X }
- X if (found && !all)
- X exit(0);
- X }
- X
- X if (!(path = getenv("PATH"))) {
- X fprintf(stderr, "%s: no PATH in environment!\n", Prog);
- X exit(1);
- X }
- X
- X if (!*path)
- X path = "."; /* another dubious convention */
- X
- X pathv = convert(path); /* convert path string to vector */
- X
- X if (!*argv) { /* print path if no more arguments */
- X while (*pathv)
- X puts(*pathv++);
- X exit(0);
- X }
- X
- X uid = geteuid();
- X gid = getegid();
- X if (uid == 0) {
- X xmask = X_ALL;
- X rmask = R_ALL;
- X }
- X
- X for (p = pathv; path = *p++; ) { /* try every component */
- X s = buf;
- X while (*s++ = *path++)
- X ;
- X (void) strcpy(s, *argv);
- X *--s = '/';
- X
- X if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
- X continue;
- X
- X /* file exists and is regular */
- X
- X if (uid != 0) {
- X mask = st.st_uid == uid ? M_USR :
- X st.st_gid == gid ? M_GRP :
- X#ifdef MULTIPLE_GROUPS
- X groups_member(st.st_gid) ? M_GRP :
- X#endif /* MULTIPLE_GROUPS */
- X M_OTH;
- X xmask = X_ALL & mask;
- X rmask = R_ALL & mask;
- X }
- X
- X if (!(st.st_mode & xmask))
- X continue;
- X
- X /* file is executable */
- X
- X *s = 0;
- X if (stat(buf, &st) != 0) {
- X perror(buf);
- X continue;
- X }
- X
- X /* warn user if the directory is unreadable */
- X
- X if (!(st.st_mode & rmask))
- X fprintf(stderr,
- X "%s: %s found in unreadable directory `%s'!\n",
- X Prog, *argv, buf);
- X
- X *s = '/';
- X puts(buf);
- X if (!all)
- X exit(0);
- X found = 1;
- X }
- X
- X if (found)
- X exit(0);
- X
- X fprintf(stderr, "%s not found in:\n", *argv);
- X while (*pathv)
- X fprintf(stderr, "%s\n", *pathv++);
- X exit(1);
- X /* NOTREACHED */
- X}
- X
- X
- Xchar **convert(path)
- Xchar *path;
- X{
- X register char *s, c;
- X register int pathc; /* the length of the path vector */
- X char **v, **pathv, *malloc();
- X
- X for (s = path, pathc = 2; c = *s++; )
- X if (c == ':')
- X ++pathc;
- X
- X if (!(pathv = (char **) malloc(pathc * sizeof(char *)))) {
- X perror("malloc");
- X exit(1);
- X }
- X
- X for (s = path, v = pathv; (c = *s) != '\0'; ) {
- X if (c == ':') {
- X /*
- X * This colon is spurious. According to some
- X * dubious convention it is made equivalent to a dot.
- X */
- X *v++ = ".";
- X if (*++s == '\0')
- X *v++ = ".";
- X /*
- X * The PATH ended in a spurious colon.
- X * To be consistent we add another dot
- X * to the path vector. One day you'll
- X * be glad we did.
- X */
- X } else {
- X *v++ = s;
- X while ((c = *++s) != '\0')
- X if (c == ':') {
- X *s++ = '\0';
- X if (*s == '\0')
- X *v++ = ".";
- X /*
- X * The PATH ended in a
- X * (spurious) colon, so
- X * add dot to the vector.
- X */
- X break;
- X }
- X }
- X }
- X
- X *v = 0; /* Signal the end of the path vector. */
- X
- X return pathv;
- X}
- X
- X
- X#ifdef MULTIPLE_GROUPS
- Xint groups_member(gid)
- Xint gid;
- X{
- X register
- X int *p, ngroups;
- X int groups[NGROUPS];
- X
- X if ((ngroups = getgroups(NGROUPS, groups)) < 0)
- X return 0;
- X p = groups;
- X while (--ngroups >= 0)
- X if (*p++ == gid)
- X return 1;
- X return 0;
- X}
- X#endif /* MULTIPLE_GROUPS */
- + END-OF-FILE which6.c
- chmod 'u=rw,g=r,o=r' 'which6.c'
- set `wc -c 'which6.c'`
- count=$1
- case $count in
- 5970) :;;
- *) echo 'Bad character count in ''which6.c' >&2
- echo 'Count should be 5970' >&2
- esac
- echo Extracting 'which.1'
- sed 's/^X//' > 'which.1' << '+ END-OF-FILE ''which.1'
- X.TH WHICH 1 Apr\ 04\ 1990
- X.SH NAME
- Xwhich \- give alias, function or path expansion of command
- X.SH SYNOPSIS
- X.B which
- X[
- X.B \-i
- X] [
- X.B \-a
- X] [
- X.B \-\-
- X] [
- X.I command
- X]
- X.SH DESCRIPTION
- X.I Which
- Xprovides the user with the full expansion of the
- X.I command
- Xargument, be it either an \fIalias\fR, a \fIshell function\fR
- Xor an executable file (default). To enable search for
- X.I aliases
- Xand \fIshell functions\fR
- Xthe user should supply the `\fI\-i\fR'
- X(= interactive) flag. In that case
- X.I which
- Xexpects as standard input the expansion of the \fIalias\fR
- Xor \fIshell function\fR.
- XIf the standard input is empty or the `\fI\-i\fR' flag has not been
- Xgiven, \fIwhich\fR will try to locate \fIcommand\fR
- Xin the user's \fBPATH\fR.
- XThe interactive mode is easily used by setting an
- X.I alias
- Xlike the following:
- X.ft B
- X.nf
- X
- X alias which alias !\\$ \\| /usr/local/bin/which \-i !\\*
- X
- X.fi
- X.ft R
- Xin \fIcsh\fR, or
- X.ft B
- X.nf
- X
- X alias which eval alias '\\"\\$$#\\" |' \\
- X /usr/local/bin/which \-i '${1+"$@"}'
- X
- X.fi
- X.ft R
- Xin shells which are supersets of
- X.I sh
- Xand which know \fIaliases\fR. If your shell has \fIshell functions\fR, you
- Xcan use the following function:
- X.ft B
- X.nf
- X
- X which()
- X {
- X eval last=\\"\\$$#\\"
- X set | sed \-n "/^$last(){$/,/^}$/p" |
- X /usr/local/bin/which \-i ${1+"$@"}
- X }
- X
- X.fi
- X.ft R
- XIf the `\fI\-a\fR' (= all) flag is given,
- X.I which
- Xwill not stop after the first `match', but search for all occurrences of
- X.I command
- Xin the user's
- X.B PATH.
- XThe `\fI\-\-\fR'
- Xflag can be used to end the list of options: the next argument (if present)
- Xwill be taken as \fIcommand\fR, even if it starts with a `\-'.
- X\fIWhich [\-i] [\-a] [\-\-]\fR
- Xwithout further arguments prints the user's
- X.B PATH
- Xbroken up into its components,
- Xone per line.
- X.PP
- XThis new version of the
- X.I which
- Xcommand is not a
- X.I csh
- Xscript.
- XBeing an executable it is much faster, and not sourcing
- X.I .cshrc
- Xit gives a true picture of one's
- X.I aliases.
- XFurthermore it will give the correct answers even if:
- X.IP \-
- Xthe \fIeffective uid\fR
- X(\fIgid\fR) differs from the \fIreal\fR uid (gid)
- X.IP \-
- Xthe effective uid is 0 (\fIroot\fR).
- X.SH EXAMPLE
- X.ft B
- X.nf
- X% alias
- Xwhich alias !$ | /usr/local/bin/which \-i !*
- X% which which
- Xwhich alias !$ | /usr/local/bin/which \-i !*
- X% which \-a which
- Xwhich alias !$ | /usr/local/bin/which \-i !*
- X/usr/local/bin/which
- X/usr/ucb/which
- X%
- X.fi
- X.ft R
- X.SH AUTHOR
- XMaarten Litmaath @ VU Informatika Amsterdam
- + END-OF-FILE which.1
- chmod 'u=rw,g=r,o=r' 'which.1'
- set `wc -c 'which.1'`
- count=$1
- case $count in
- 2384) :;;
- *) echo 'Bad character count in ''which.1' >&2
- echo 'Count should be 2384' >&2
- esac
- echo Extracting 'Makefile'
- sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile'
- X# Makefile for /usr/local/bin/which
- X# If your operating system does not support multiple groups (see getgroups(2)
- X# on BSD-derivatives), comment out the next line.
- XMULTIPLE_GROUPS=-DMULTIPLE_GROUPS
- X
- Xwhich: which6.c
- X cc -O $(MULTIPLE_GROUPS) -o which which6.c
- X
- Xinstall: which doc
- X /bin/mv -f which /usr/local/bin
- X /bin/mv -f which.man /usr/local/man/cat1/which.1
- X /bin/cp which.1 /usr/local/man/man1
- X
- Xdoc:
- X nroff -man which.1 > which.man
- + END-OF-FILE Makefile
- chmod 'u=rw,g=r,o=r' 'Makefile'
- set `wc -c 'Makefile'`
- count=$1
- case $count in
- 443) :;;
- *) echo 'Bad character count in ''Makefile' >&2
- echo 'Count should be 443' >&2
- esac
- exit 0
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-
-